package com.example.xposedhook;

import android.util.Log;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

import static com.example.xposedhook.Utils.object2Bytes;
import static com.example.xposedhook.Utils.parameterLog;
import static com.example.xposedhook.Utils.printParms;
import static com.example.xposedhook.Utils.returnValueLog;

public class MyHook implements IXposedHookLoadPackage {
    public static String TAG = "hlzds";

    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        TAG = ":"+lpparam.processName;
        Log.d(TAG,"HOOK...");

        try{
            XposedBridge.hookAllConstructors(XposedHelpers.findClass("javax.crypto.spec.DESKeySpec", lpparam.classLoader), new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);
                    byte[] keybyte = new byte[8];
                    int offset = 0;
                    if(param.args.length!=1){
                        offset = ((Integer)param.args[1]).intValue();
                    }
                    System.arraycopy((byte[])param.args[0],offset,keybyte,0,8);

                    parameterLog(keybyte,"3DESKey");
                }
            });
            XposedBridge.hookAllConstructors(XposedHelpers.findClass("javax.crypto.spec.DESedeKeySpec", lpparam.classLoader), new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);
                    byte[] keybyte = new byte[24];
                    int offset = 0;
                    if(param.args.length!=1){
                        offset = ((Integer)param.args[1]).intValue();
                    }
                    System.arraycopy((byte[])param.args[0],offset,keybyte,0,24);
                    parameterLog(keybyte,"3DESKey");
                }
            });
            XposedBridge.hookAllConstructors(XposedHelpers.findClass("javax.crypto.spec.SecretKeySpec", lpparam.classLoader), new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);
                    byte[] secretKey = (byte[])param.args[0];
                    int offset = 0;
                    int size = 0;
                    String algorithm = null;
                    if(param.args.length!=2){
                        offset = ((Integer)param.args[1]).intValue();
                        size = ((Integer)param.args[2]).intValue();
                        algorithm = (String)param.args[3];
                    }else{
                        size = secretKey.length;
                        algorithm = (String)param.args[1];
                    }
                    byte[] keybyte = new byte[size];
                    System.arraycopy(secretKey,offset,keybyte,0,size);

                    parameterLog(keybyte,algorithm+"  SecretKey");
                }
            });
            XposedBridge.hookAllConstructors(XposedHelpers.findClass("java.security.spec.X509EncodedKeySpec", lpparam.classLoader), new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);
                    byte[] keybyte = (byte[])param.args[0];
                    parameterLog(keybyte,"X509Key");
                }
            });
            XposedBridge.hookAllConstructors(XposedHelpers.findClass("java.security.spec.RSAPublicKeySpec", lpparam.classLoader), new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);
                    Utils.logD("RSAPublicKeySpec 参数1: "+param.args[0]);
                    Utils.logD("RSAPublicKeySpec 参数2: "+param.args[1]);

                }
            });
            XposedBridge.hookAllConstructors(XposedHelpers.findClass("javax.crypto.spec.IvParameterSpec", lpparam.classLoader), new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);
                    byte[] imParameter = (byte[])param.args[0];
                    int offset = 0;
                    int size = 0;
                    if(param.args.length!=1){
                        offset = ((Integer)param.args[1]).intValue();
                        size = ((Integer)param.args[2]).intValue();
                    }else{
                        size = imParameter.length;
                    }
                    byte[] ivbyte = new byte[size];
                    System.arraycopy(imParameter,offset,ivbyte,0,size);
                    parameterLog(ivbyte,"imParameterKey");
                }
            });
            XposedBridge.hookAllMethods(XposedHelpers.findClass("javax.crypto.Mac", lpparam.classLoader), "doFinal", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);

                    if(param.args.length == 2) return;
                    Mac mac = (Mac)param.thisObject;
                    String algorithm = mac.getAlgorithm();
                    if(param.args.length==1){
                        parameterLog((byte[])param.args[0],algorithm);
                    }
                    byte[] res = object2Bytes(param.getResult());
                    returnValueLog(res,algorithm);
                }
            });
            XposedBridge.hookAllMethods(XposedHelpers.findClass("javax.crypto.Cipher", lpparam.classLoader), "doFinal", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);

                    Cipher cip = (Cipher)param.thisObject;
                    String algorithm = cip.getAlgorithm();
                    byte[] dataAll = (byte[])param.args[0];
                    if(param.args.length==3){
                        int offset = ((Integer)param.args[1]).intValue();
                        int size = ((Integer)param.args[2]).intValue();
                        byte[] dataByte = new byte[size];
                        System.arraycopy(dataAll,offset,dataByte,0,size);
                        parameterLog(dataByte,algorithm);
                    }else if(param.args.length==1){
                        parameterLog(dataAll,algorithm);
                    }
                    byte[] res = object2Bytes(param.getResult());
                    returnValueLog(res,algorithm);
                }
            });

            XposedHelpers.findAndHookMethod("java.security.MessageDigest", lpparam.classLoader, "update",byte[].class,
                new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                        MessageDigest md = (MessageDigest)param.thisObject;
                        Utils.logD(md.getAlgorithm()+" update: "+new String((byte[])param.args[0]));
                    }
            });

            XposedBridge.hookAllMethods(XposedHelpers.findClass("java.security.KeyFactory", lpparam.classLoader), "generatePrivate", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);
                    PrivateKey pk = (PrivateKey)param.getResult();

                    X509EncodedKeySpec x509 =(X509EncodedKeySpec)param.args[0];
                    parameterLog(x509.getEncoded(),pk.getAlgorithm());
                }
            });
            XposedBridge.hookAllMethods(XposedHelpers.findClass("java.security.KeyFactory", lpparam.classLoader), "generatePublic", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);
                    PublicKey pk = (PublicKey)param.getResult();
                    X509EncodedKeySpec x509 =(X509EncodedKeySpec)param.args[0];
                    parameterLog(x509.getEncoded(),pk.getAlgorithm());
                }
            });
            XposedBridge.hookAllMethods(XposedHelpers.findClass("java.security.MessageDigest", lpparam.classLoader), "digest", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);
                    MessageDigest md = (MessageDigest)param.thisObject;
                    if(param.args != null && param.args.length >=1 ) {
                        parameterLog((byte[])param.args[0],md.getAlgorithm());
                    }
                    byte[] res = object2Bytes(param.getResult());
                    returnValueLog(res,md.getAlgorithm());
                }
            });
            XposedBridge.hookAllMethods(XposedHelpers.findClass("java.security.PublicKey", lpparam.classLoader), "generatePublic", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Log.e(TAG,"函數调用栈",new Throwable("stack dump"));
                    printParms(param);
                    PublicKey res = (PublicKey)param.getResult();
                    returnValueLog(res.getEncoded(),"RSAKey");
                }
            });

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}